# -*- coding: utf-8 -*-
import KBEngine
import IKernel
import time
import random
import xml.dom.minidom
import CardDef
import copy

from KBEDebug import *

def Instance():
	from logic import ModuleMgr
	return ModuleMgr.Instance().getModule("PlayModule")

class PlayModule:

	def __init__(self):
		pass

	def init(self, isReload):
		pass

	def isQiangDizhu(self, playerEntityID):
		return False

	def isCrossruff(self, playerEntityID):
		return False

	def getPlayoutCards(self, playerEntityID):
		"""
		获取要出的显示牌
		playoutCardsInfo[0] int32 牌类型
		playoutCardsInfo[1] list  多张显示牌
		"""
		if self.isCrossruff(playerEntityID) == False:
			#不是对手牌(也就是自家牌), 那就不要
			return [CardDef.PlayoutCardType.Invalid, []]

		playerEntity = KBEngine.entities.get(playerEntityID)
		roomEntity = KBEngine.entities.get(playerEntity.roomEntityID)
		if roomEntity.lastPlayoutCardType == CardDef.PlayoutCardType.Wangzha:
			#王炸要不起
			return [CardDef.PlayoutCardType.Invalid, []]

		#上次牌权重
		lastCardWeight = self.getCardsWeight(roomEntity.lastPlayoutCardType, roomEntity.lastPlayoutCards)
		ablePlayoutCardTypes = self.getAblePlayoutCardType(roomEntity.lastPlayoutCardType)
		if len(ablePlayoutCardTypes) == 0:
			return [CardDef.PlayoutCardType.Invalid, []]

		dispatcher = {
			CardDef.PlayoutCardType.Danzhang	: self.getDanzhang,
			CardDef.PlayoutCardType.Duizi		: self.getDuizi,
			CardDef.PlayoutCardType.Sanbudai	: self.getSanbudai,
			CardDef.PlayoutCardType.Sandaiyi	: self.getSandaiyi,
			CardDef.PlayoutCardType.Liandui		: self.getLiandui,
			CardDef.PlayoutCardType.Shunzi		: self.getShunzi,
			CardDef.PlayoutCardType.Zhadan		: self.getZhaDan,
			CardDef.PlayoutCardType.Sidaiyi		: self.getSiDaiyi,
			CardDef.PlayoutCardType.Sidaier		: self.getSiDaier,
			CardDef.PlayoutCardType.Wangzha		: self.getWangZha,
		}

		# 默认返回值
		playoutCardsInfo = [CardDef.PlayoutCardType.Invalid, []]
		weightCards = self.showCard2WeightCard(playerEntity.handCards)
		willPlayoutWeightCards = []
		for cardType in ablePlayoutCardTypes:
			funcAddr = dispatcher.get(cardType)
			if funcAddr == None:
				continue

			willPlayoutWeightCards = funcAddr(weightCards)
			if len(willPlayoutWeightCards) != 0:
				playoutCardsInfo[0] = cardType
				break

		if len(willPlayoutWeightCards) == 0:
			return [CardDef.PlayoutCardType.Invalid, []]

		willPlayoutShowCards = self.weightCard2ShowCardFromShowCards(playerEntity.handCards, willPlayoutWeightCards)
		if len(willPlayoutShowCards) == 0:
			return [CardDef.PlayoutCardType.Invalid, []]

		playoutCardsInfo[1].extend(willPlayoutShowCards)
		return playoutCardsInfo

	def canPlayout(self, playerEntityID, playoutCardType, playoutCards):
		"""
		是否是有效的出牌
		"""
		#当前牌的权重
		curCardWeight = self.getCardsWeight(playoutCardType, playoutCards)
		if curCardWeight == 0:
			return False

		# 王炸的牌最大
		if playoutCardType == CardDef.PlayoutCardType.Wangzha:
			return True

		playerEntity = KBEngine.entities.get(playerEntityID)
		roomEntity = KBEngine.entities.get(playerEntity.roomEntityID)
		#上次牌类型权重
		lastCardTypeWeight = CardDef.PlayoutCardTypeWeight.get(roomEntity.lastPlayoutCardType)
		if lastCardTypeWeight == None:
			return True

		# 当前牌类型权重
		curCardTypeWeight = CardDef.PlayoutCardTypeWeight.get(playoutCardType)
		if curCardTypeWeight < lastCardTypeWeight:
			return False
		elif curCardTypeWeight > lastCardTypeWeight:
			# 牌类型权重大于上次的，直接可以出牌了
			return True

		if len(playoutCards) != len(roomEntity.lastPlayoutCards):
			return False

		#上次牌权重
		lastCardWeight = self.getCardsWeight(roomEntity.lastPlayoutCardType, roomEntity.lastPlayoutCards)
		if curCardWeight <= lastCardWeight:
			return False

		return True

	def getAblePlayoutCardType(self, curCardType):
		"""
		获取能打的类型牌
		"""
		curCardTypeWeight = CardDef.PlayoutCardTypeWeight.get(curCardType)
		if curCardTypeWeight == None:
			return []

		ablePlayoutType = []
		for cardType, weight in CardDef.PlayoutCardTypeWeight.items():
			if weight >= curCardTypeWeight:
				ablePlayoutType.append(cardType)

		ablePlayoutType.sort()
		return ablePlayoutType

	def formatWeightToCountCards(self, weightCards):
		"""
		格式化权重到出现次数牌
		"""
		fmtWeightCards = {}
		for weightCard in weightCards:
			cnt = fmtWeightCards.get(weightCard)
			if cnt == None:
				cnt = 0
			fmtWeightCards[weightCard] = cnt + 1

		return fmtWeightCards

	def formatCountToWeightCards(self, weightCards):
		"""
		格式化出现次数到权重牌
		"""
		w2cCards = self.formatWeightToCountCards(weightCards)

		fmtWeightCards = {}
		for weightCard, cnt in w2cCards.items():
			if fmtWeightCards.get(cnt) == None:
				fmtWeightCards[cnt] = []
			fmtWeightCards[cnt].append(weightCard)

		return fmtWeightCards

	def getDanzhang(self, weightCards, minWeight, length):
		cntToWeightCards = self.formatCountToWeightCards(weightCards)
		# 从单张牌中获取一张
		danzhangWeightCards = cntToWeightCards.get(1)
		if danzhangWeightCards != None:
			return [danzhangWeightCards[0]]

		# 从对子牌中获取一张
		duiziWeightCards = cntToWeightCards.get(2)
		if duiziWeightCards != None:
			return [duiziWeightCards[0]]

		return []

	def getDuizi(self, weightCards, minWeight, length):
		fmtWeightCards = self.formatWeightToCountCards(weightCards)
		for weightCard, cnt in fmtWeightCards.items():
			if weightCard <= minWeight:
				continue

			if cnt == 2:
				return [weightCard]

		return []

	def getLiandui(self, weightCards, minWeight, length):
		fmtWeightCards = self.formatWeightToCountCards(weightCards)
		noRepWeightCards = list(fmtWeightCards.keys())
		noRepWeightCards.sort()
		if len(noRepWeightCards) < 3 \
			or (length != 0 and len(noRepWeightCards) < length):
			return []

		retWeightCards = []
		for i in range(1, len(noRepWeightCards)):
			lastWeightCard = noRepWeightCards[i - 1]
			curWeightCard = noRepWeightCards[i]
			if lastWeightCard <= minWeight \
				or fmtWeightCards[lastWeightCard] < 2 \
				or lastWeightCard + 1 != curWeightCard:
				retWeightCards = []
				continue

			if length != 0 and len(retWeightCards) >= length:
				break

			if lastWeightCard >= CardDef.DapaiWeight: 
				if length == 0:
					if len(retWeightCards) >= 3:
						return retWeightCards
				else:
					if len(retWeightCards) > length:
						return retWeightCards
				# 由于noRepWeightCards已经是升序排好了，到了顺子最大值，后面不用检测了
				return []

			retWeightCards.append(lastWeightCard)
			if i == len(noRepWeightCards) - 1 \
				and (length == 0 or len(retWeightCards) < length) \
				and curWeightCard < CardDef.DapaiWeight:
				#最后一个了，并且没有达到想要的长度
				retWeightCards.append(curWeightCard)

		if length == 0:
			if len(retWeightCards) < 3:
				return []
		else:
			if len(retWeightCards) < length:
				return []

		return retWeightCards

	def getShunzi(self, weightCards, minWeight, length):
		"""
		length == 0 的时候，就按照权重牌，获取尽量长的顺子
		"""
		fmtWeightCards = self.formatWeightToCountCards(weightCards)
		noRepWeightCards = list(fmtWeightCards.keys())
		noRepWeightCards.sort()
		#顺子最短也要大于5
		if len(noRepWeightCards) < 5 \
			or (length != 0 and len(noRepWeightCards) < length):
			return []

		retWeightCards = []
		for i in range(1, len(noRepWeightCards)):
			lastWeightCard = noRepWeightCards[i - 1]
			curWeightCard = noRepWeightCards[i]
			if lastWeightCard <= minWeight \
				or lastWeightCard + 1 != curWeightCard:
				retWeightCards = []
				continue

			if length != 0 and len(retWeightCards) >= length:
				break

			if lastWeightCard >= CardDef.DapaiWeight: 
				if length == 0:
					if len(retWeightCards) >= 5:
						return retWeightCards
				else:
					if len(retWeightCards) > length:
						return retWeightCards
				# 由于noRepWeightCards已经是升序排好了，到了顺子最大值，后面不用检测了
				return []

			retWeightCards.append(lastWeightCard)
			if i == len(noRepWeightCards) - 1 \
				and (length == 0 or len(retWeightCards) < length) \
				and curWeightCard < CardDef.DapaiWeight:
				#最后一个了，并且没有达到想要的长度
				retWeightCards.append(curWeightCard)

		if length == 0:
			if len(retWeightCards) < 5:
				return []
		else:
			if len(retWeightCards) < length:
				return []

		return retWeightCards

	def getSanbudai(self, weightCards, minWeight, length):
		cntToWeightCards = self.formatCountToWeightCards(weightCards)
		# 获取3张牌的
		sanzhangWeightCards = cntToWeightCards.get(3)
		if sanzhangWeightCards == None:
			return []
		sanzhangWeightCard = 0
		for weightCard in sanzhangWeightCards:
			if weightCard <= minWeight:
				continue
			sanzhangWeightCard = weightCard
			break

		if sanzhangWeightCard == 0:
			return []

		return [sanzhangWeightCard, sanzhangWeightCard, sanzhangWeightCard]

	def getSandaiyi(self, weightCards, minWeight, length):
		sanzhangWeightCards = self.getSanbudai(weightCards, minWeight, length)
		if len(sanzhangWeightCards) == 0:
			return  []

		cntToWeightCards = self.formatCountToWeightCards(weightCards)
		daiyiWeightCards = cntToWeightCards.get(1)
		if daiyiWeightCards == None:
			daiyiWeightCards = cntToWeightCards.get(2)
			if daiyiWeightCards == None:# 如果没有单张牌和对子牌那就返回空了
				return []
		daiyiWeightCard = 0
		for weightCard in daiyiWeightCards:
			if weightCard >= CardDef.DapaiWeight and cardsNum != 4:
				continue
			daiyiWeightCard = weightCard
			break
		if daiyiWeightCard == 0:
			return []

		sandaiyiWeightCards = []
		sandaiyiWeightCards.extend(sanzhangWeightCards)
		sandaiyiWeightCards.append(daiyiWeightCard)
		return sandaiyiWeightCards

	def getZhaDan(self, weightCards, minWeight, length):
		fmtWeightCards = self.formatWeightToCountCards(weightCards)
		for weightCard, cnt in fmtWeightCards.items():
			if cnt < 4 or weightCard < minWeight:
				continue
			return [weightCard, weightCard, weightCard, weightCard]

		return []

	def getSiDaiyi(self, weightCards, minWeight, length):
		bakWeightCards = copy.deepcopy(weightCards)
		zhadanWeightCards = self.getZhaDan(bakWeightCards, minWeight, length)
		if len(zhadanWeightCards) == 0:
			return []

		# 移除炸弹所用的牌
		for weightCard in zhadanWeightCards:
			bakWeightCards.remove(weightCard)

		danyiWeightCards = self.getDanzhang(bakWeightCards, CardDef.MinWeightCard, length)
		# 没单张的话，就拆对子
		if len(danyiWeightCards) == 0:
			danyiWeightCards = self.getDuizi(bakWeightCards, CardDef.MinWeightCard, length)
			if len(danyiWeightCards) == 0:
				return []

		zhadanWeightCards.append(danyiWeightCards[0])
		return zhadanWeightCards

	def getSiDaier(self, weightCards, minWeight, length):
		bakWeightCards = copy.deepcopy(weightCards)
		zhadanWeightCards = self.getZhaDan(bakWeightCards, minWeight, length)
		if len(zhadanWeightCards) == 0:
			return []

		# 移除炸弹所用的牌
		for weightCard in zhadanWeightCards:
			bakWeightCards.remove(weightCard)

		daierWeightCards = []
		for i in range(0, 2):
			danzhangWeightCards = self.getDanzhang(bakWeightCards, CardDef.MinWeightCard, length)
			if len(danzhangWeightCards) == 0:
				daierWeightCards = []
				break
			else:
				daierWeightCards.extend(danzhangWeightCards)

		if len(daierWeightCards) != 0:
			zhadanWeightCards.extend(daierWeightCards)
			return zhadanWeightCards

		duiziWeightCards = self.getDuizi(bakWeightCards, CardDef.MinWeightCard, length)
		if len(duiziWeightCards) == 0:
			return []

		zhadanWeightCards.extend(duiziWeightCards)
		return zhadanWeightCards

	def getWangZha(self, weightCards, minWeight, length):
		fmtWeightCards = self.formatWeightToCountCards(weightCards)
		if fmtWeightCards.get(CardDef.XiaoWangWeight) == None \
			or fmtWeightCards.get(CardDef.DaWangWeight) == None:
			return []

		return [CardDef.XiaoWangWeight, CardDef.DaWangWeight]

	def getCardsWeight(self, playoutCardType, showCards):
		dispatcher = {
			CardDef.PlayoutCardType.Danzhang	: self.getDanzhangWeight,
			CardDef.PlayoutCardType.Duizi		: self.getDuiziWeight,
			CardDef.PlayoutCardType.Sanbudai	: self.getShanBuDaiWeight,
			CardDef.PlayoutCardType.Sandaiyi	: self.getShanDaiyiWeight,
			CardDef.PlayoutCardType.Liandui		: self.getLianduiWeight,
			CardDef.PlayoutCardType.Shunzi		: self.getShunziWeight,
			CardDef.PlayoutCardType.Zhadan		: self.getZhaDanWeight,
			CardDef.PlayoutCardType.Sidaiyi		: self.getSiDaiyiWeight,
			CardDef.PlayoutCardType.Sidaier		: self.getSiDaierWeight,
			CardDef.PlayoutCardType.Wangzha		: self.isWangzha,
		}
		funcAddr = dispatcher.get(playoutCardType)
		if funcAddr == None:
			return 0

		weightCards = self.showCard2WeightCard(showCards)
		return funcAddr(weightCards)

	def showCard2WeightCard(self, showCards):
		"""
		显示牌转成权重牌
		"""
		weightCards = []
		for showCard in showCards:
			weight = CardDef.CardWeight.get(showCard)
			if weight == None:
				continue
			weightCards.append(weight)

		weightCards.sort()
		return weightCards

	def weightCard2ShowCardFromShowCards(self, showCards, weightCards):
		bakShowCards = copy.deepcopy(showCards)
		retShowCards = []
		for weightCard in weightCards:
			matchAllShowCards = CardDef.WeightToCards.get(weightCard)
			if matchAllShowCards == None:
				return []

			isFound = False
			for matchShowCard in matchAllShowCards:
				if matchShowCard in bakShowCards:
					bakShowCards.remove(matchShowCard)
					retShowCards.append(matchShowCard)
					isFound = True

			if isFound == False:
				return []

		return retShowCards

	def getDanzhangWeight(self, weightCards):
		if len(weightCards) != 1:
			return 0

		return weightCards[0]

	def getShunziWeight(self, weightCards):
		"""
		获得顺子的权重，
		无效返回0
		有效返回顺子中最小的权重值
		"""
		if len(weightCards) < 5:
			return 0

		weightCards.sort()
		if weightCards[0] < CardDef.ShunziMinWeight \
			or weightCards[len(weightCards) - 1] > CardDef.ShunziMinWeight:
			# 超出顺子的范围
			return 0

		i = 0
		while i < len(weightCards) - 1:
			if weightCards[i] + 1 != weightCards[i + 1]:
				# 顺子不是连续的
				return 0

		return weightCards[0]

	def getDuiziWeight(self, weightCards):
		"""
		获得对子的权重，
		无效返回0
		有效返回对子中的权重值
		"""
		if len(weightCards) != 2 or weightCards[0] != weightCards[1]:
			return 0

		return weightCards[0]

	def getLianduiWeight(self, weightCards):
		if len(weightCards) % 2 != 0:
			return 0

		# value   出现的次数
		# key     牌权重
		fmtWeightCards = {}
		for weightCard in weightCards:
			if fmtWeightCards.get(weightCard) == None:
				fmtWeightCards[weightCard] = 0

			cnt = fmtWeightCards[weightCard]
			fmtWeightCards[weightCard] = cnt + 1

		if len(fmtWeightCards) < 3:
			return 0

		keysList = list(fmtWeightCards.keys())
		keysList.sort()

		for i in range(0, len(keysList) - 1):
			weightCard = keysList[i]
			nextWeightCard = keysList[i + 1]
			if fmtWeightCards[weightCard] != 2 \
				or fmtWeightCards[nextWeightCard] != 2 \
				or weightCard + 1 != nextWeightCard:
				return 0

		return keysList[0]

	def getShanDaiyiWeight(self, weightCards):
		if len(weightCards) != 4:
			return 0

		# value   出现的次数
		# key     牌权重
		fmtWeightCards = {}
		for weightCard in weightCards:
			if fmtWeightCards.get(weightCard) == None:
				fmtWeightCards[weightCard] = 0
			cnt = fmtWeightCards[weightCard]
			fmtWeightCards[weightCard] = cnt + 1

		if len(fmtWeightCards) != 2:
			return 0

		for weightCard, cnt in fmtWeightCards.items():
			if cnt == 3:
				return weightCard

		return 0

	def getShanBuDaiWeight(self, weightCards):
		if len(weightCards) != 3:
			return 0

		for i in range(0, len(weightCards) - 1):
			if weightCards[i] != weightCards[i + 1]:
				return 0

		return weightCards[0]

	def getZhaDanWeight(self, weightCards):
		if len(weightCards) != 4:
			return 0

		for i in range(0, len(weightCards) - 1):
			if weightCards[i] != weightCards[i + 1]:
				return 0

		return weightCards[0]

	def getSiDaiyiWeight(self, weightCards):
		if len(weightCards) != 5:
			return 0

		# value   出现的次数
		# key     牌权重
		fmtWeightCards = {}
		for weightCard in weightCards:
			if fmtWeightCards.get(weightCard) == None:
				fmtWeightCards[weightCard] = 0
			cnt = fmtWeightCards[weightCard]
			fmtWeightCards[weightCard] = cnt + 1

		for weightCard, cnt in fmtWeightCards.items():
			if cnt == 4:
				return weightCard

		return 0

	def getSiDaierWeight(self, weightCards):
		if len(weightCards) != 6:
			return 0

		# value   出现的次数
		# key     牌权重
		fmtWeightCards = {}
		for weightCard in weightCards:
			if fmtWeightCards.get(weightCard) == None:
				fmtWeightCards[weightCard] = 0
			cnt = fmtWeightCards[weightCard]
			fmtWeightCards[weightCard] = cnt + 1

		for weightCard, cnt in fmtWeightCards.items():
			if cnt == 4:
				return weightCard

		return 0

	def isWangzha(self, weightCards):
		if len(weightCards) != 2:
			return 0

		# value   出现的次数
		# key     牌权重
		fmtWeightCards = {}
		for weightCard in weightCards:
			if fmtWeightCards.get(weightCard) == None:
				fmtWeightCards[weightCard] = 0
			cnt = fmtWeightCards[weightCard]
			fmtWeightCards[weightCard] = cnt + 1

		xiaoWangCnt = fmtWeightCards.get(CardDef.XiaoWangWeight)
		daWangCnt = fmtWeightCards.get(CardDef.DaWangWeight)
		if xiaoWangCnt == None or xiaoWangCnt != 1 \
		 or daWangCnt == None or daWangCnt != 1:
			return 0

		return 1





